// C语言共用基本库
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

// 使用GPIO库，用来定义GPIO模式，高低电平等
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "iot_gpio.h"

// 传感器所用库adc读取可燃气体所用，aht20, iot_i2c为读取温湿度所用
// 其他为传感器共用基本库
#include "hi_adc.h"
#include "aht20.h"
#include "iot_i2c.h"
#include "iot_errno.h"
#include "hi_io.h"

// UDP协议库，用来创建和发送UDP数据集
#include "wifi_device.h"
#include "lwip/netifapi.h"
#include "lwip/sockets.h"
#include "lwip/api_shell.h"
#include <arpa/inet.h>

// hal的wifi和mqtt协议库
#include "hal_bsp_wifi.h"
#include "hal_bsp_mqtt.h"
#include "hal_bsp_ap3216c.h"
#include "hal_bsp_aw2013.h"
#include "hal_bsp_pcf8574.h"
#include "hal_bsp_sht20.h"
#include "hal_bsp_ssd1306.h"
#include "hal_bsp_structAll.h"

// 第三方cJSON库，方便接收和发送JSON数据
#include "cJSON.h"

// wifi名称，替换为自己的名称
#define WIFI_NAME "Elysia"
// wifi密码，替换为自己的密码
#define WIFI_PASSWORD "1817731580"

// UDP服务器的IP
#define UDP_SERVER_IP "10.219.31.221"
// UDP服务器的密码
#define UDP_SERVER_PORT 49944

// 设备ID
#define DEVICE_ID "660974affb8177243a534265_hi3861"
// MQTT客户端ID
#define MQTT_CLIENT_ID "660974affb8177243a534265_hi3861_0_0_2024111304"
// MQTT用户名
#define MQTT_USER_NAME "660974affb8177243a534265_hi3861"
// MQTT密码
#define MQTT_PASS_WORD "9ad3d9cb1c230aeb29b7e3b868c1c89823dbc6f66f995267ffaa378f5f6d113a"
// 华为iotda的IP地址
#define SERVER_IP_ADDR "121.36.42.100" // 固定，无特殊情况请勿更改
// 华为iotda的的IP端口号
#define SERVER_IP_PORT 1883 // 固定，无特殊情况请勿更改
// 控制命令接受主题
#define MQTT_TOPIC_SUB_COMMANDS "$oc/devices/%s/sys/commands/#"
// 控制命令返回主题
#define MQTT_TOPIC_PUB_COMMANDS_REQ "$oc/devices/%s/sys/commands/response/request_id=%s"
#define MALLOC_MQTT_TOPIC_PUB_COMMANDS_REQ "$oc/devices//sys/commands/response/request_id="

// 从设备上传数据的主题
#define MQTT_TOPIC_PUB_PROPERTIES "$oc/devices/%s/sys/properties/report"
#define MALLOC_MQTT_TOPIC_PUB_PROPERTIES "$oc/devices//sys/properties/report"

// 设置引脚
// GPIO2 --> 控制LED | GPIO0 --> 控制继电器和警报器
#define LED_TASK_GPIO 2
#define SIG_TASK_GPIO 0

// 定义高低电平
#define GPIO_HIGH (1)
#define GPIO_LOW (0)

// 定义UDP指令集
#define COMMAND_SAY_HELLO "COMMAND_SAY_HELLO" // 测试指令
#define COMMAND_SET_LED_L "COMMAND_SET_LED_L" // 点亮LED
#define COMMAND_SET_LED_D "COMMAND_SET_LED_D" // 关闭LED
#define COMMAND_SET_SIG_L "COMMAND_SET_SIG_L" // 警报器和继电器置于正常状态
#define COMMAND_SET_SIG_D "COMMAND_SET_SIG_D" // 警报器和继电器置于紧急状态
#define COMMAND_SEND "COMMAND_SEND"           // 立即更新数据

#define TASK_STACK_SIZE (1024 * 10) // 分配的内存空间

// 传感器和各个元件的状态{结构体类型}
typedef struct message_sensorData
{
    uint8_t led; // LED灯当前的状态
    uint8_t sig; // 继电器和警报器当前的状态
    float tem;   // 温度
    float hum;   // 湿度
    float gas;   // 可燃气体浓度
    float ap;    // 气压
    float ur;    // 紫外线
} msg_sensorData_t;

msg_sensorData_t sensorData = {0}; // 传感器的数据的初始化

// 用来配置多线程
osThreadId_t mqtt_send_task_id; // mqtt 发布数据任务ID
osThreadId_t mqtt_recv_task_id; // mqtt 接收数据任务ID
osThreadId_t udp_id;            // UDP的任务ID
osThreadId_t read_task_id;      // read

// 定义UDP监听函数
void command_lis(const char *recvBuf)
{
    if (strcmp(recvBuf, COMMAND_SET_LED_D) == 0) // 如果接收到的数据中仅含有COMMAND_SET_LED_D指令
    {
        IoTGpioSetOutputVal(LED_TASK_GPIO, GPIO_LOW); // 将GPIO2置于低电平
        sensorData.led = 0;
        printf("LED_LOW");
    }
    else if (strcmp(recvBuf, COMMAND_SET_LED_L) == 0) // 如果接收到的数据中仅含有COMMAND_SET_LED_L指令
    {
        IoTGpioSetOutputVal(LED_TASK_GPIO, GPIO_HIGH); // 同理
        sensorData.led = 1;
        printf("LED_HIGH");
    }

    if (strcmp(recvBuf, COMMAND_SET_SIG_L) == 0) // 如果接收到的数据中仅含有COMMAND_SET_SIG_L指令
    {
        IoTGpioSetOutputVal(SIG_TASK_GPIO, GPIO_LOW); // 同理
        sensorData.sig = 0;
        printf("SIG_LOW");
    }
    else if (strcmp(recvBuf, COMMAND_SET_SIG_D) == 0) // 如果接收到的数据中仅含有COMMAND_SET_SIG_D指令
    {
        IoTGpioSetOutputVal(SIG_TASK_GPIO, GPIO_HIGH); // 同理
        sensorData.sig = 1;
        printf("SIG_HIGH");
    }

    if (strcmp(recvBuf, COMMAND_SAY_HELLO) == 0) // 如果接收到的数据中仅含有COMMAND_SAY_HELLO指令
    {
        // 如果recvBuf仅包含指令command_say_hello，触发输出hello
        printf("hello\n");
    }
}

// 设置mqtt任务的各项延迟
#define MQTT_SEND_TASK_TIME 3 // s
#define MQTT_RECV_TASK_TIME 1 // s
#define TASK_INIT_TIME 2      // s
#define DISPLAY_BUFF_MAX 64
#define MQTT_DATA_MAX 256
#define MS_PER_S 1000 // ms

// 设置可燃气体传感器所用的数据
#define GAS_SENSOR_CHAN_NAME 5
// #define GAS_SENSOR_PIN_NAME WIFI_IOT_IO_NAME_GPIO_11
#define ADC_RESOLUTION 2048
#define VOLTAGE_5V (5.0)
#define EPS (1e-7)

// 两条I2C总线的定义
#define IOT_GPIO_IDX_13 13
#define IOT_GPIO_IDX_14 14

// UDP通信状态
int ret = 0;
uint32_t retval = 0;

// MQTT和UDP数据集的BUFFFER集合
uint8_t publish_topic[MQTT_DATA_MAX] = {0};
uint8_t mqtt_data[MQTT_DATA_MAX] = {0};
uint8_t displayBuffer[DISPLAY_BUFF_MAX] = {0};

// 数据转换，用来将传感器电压数据转换为标准值
static float ConvertToVoltage(unsigned short data)
{
    return (float)data * 1.8 * 4 / 4096;
}

// 打包JSON数据
int Packaged_json_data(void)
{

    cJSON *root = NULL, *array = NULL, *services = NULL;
    cJSON *properties = NULL;
    int ret = 0;
    // 初始化工作指针

    // 组JSON数据
    root = cJSON_CreateObject(); // 创建CJSON一个对象
    services = cJSON_CreateArray();
    cJSON_AddItemToObject(root, "services", services);
    array = cJSON_CreateObject();
    cJSON_AddStringToObject(array, "service_id", "attribute");
    properties = cJSON_CreateObject();
    cJSON_AddItemToObject(array, "properties", properties);
    cJSON_AddStringToObject(properties, "led", sensorData.led ? "ON" : "OFF"); // led与sig值为0或1，在打包JSON数据时，将其映射为字符串
    cJSON_AddStringToObject(properties, "sig", sensorData.sig ? "ON" : "OFF"); // led与sig值为0或1，在打包JSON数据时，将其映射为字符串
    cJSON_AddNumberToObject(properties, "hum", sensorData.hum);
    cJSON_AddNumberToObject(properties, "tem", sensorData.tem);
    cJSON_AddNumberToObject(properties, "gas", sensorData.gas * 1e43);
    cJSON_AddNumberToObject(properties, "ap", sensorData.ap * 1e43);
    cJSON_AddNumberToObject(properties, "ur", sensorData.ur * 1e43);
    cJSON_AddItemToArray(services, array); // 将对象添加到数组中

    // 方法：
    // AddItemToObject   添加一个ITEM对象到CJSON中
    // AddStringToObject 添加一个String对象到CJSON中
    // AddNumberToObject 添加一个int对象到CJSON中

    /* 格式化打印创建的带数组的JSON对象 */
    char *str_print = cJSON_PrintUnformatted(root);
    if (str_print != NULL)
    {
        if (strcpy_s(mqtt_data, strlen(str_print) + 1, str_print) == 0)
        {
            ret = 0;
        }
        else
        {
            ret = -1;
        }
        cJSON_free(str_print);
    }
    else
    {
        ret = -1;
    }
    if (root != NULL)
    {
        cJSON_Delete(root);
    }
    else
    {
        ret = -1;
    }
    properties = str_print = root = array = services = NULL;

    return ret;
}

// MQTT发布消息到华为IOTDA
void mqtt_send_task_intime(void)
{
    // 获取设备的数据
    // 组Topic
    memset_s(publish_topic, MQTT_DATA_MAX, 0, MQTT_DATA_MAX);
    if (sprintf_s(publish_topic, MQTT_DATA_MAX, MQTT_TOPIC_PUB_PROPERTIES, DEVICE_ID) > 0)
    {
        // 组JSON数据
        Packaged_json_data();
        // 发布消息
        MQTTClient_pub(publish_topic, mqtt_data, strlen((char *)mqtt_data));
    }
}

// UDP连接任务
void udp_task_rev(void)
{
    int socket_fd = 0;
    int result;
    int cut = 0;
    // 连接基本配置

    int sockfd;
    struct sockaddr_in servaddr, cliaddr;
    char buffer[512];
    ssize_t len;
    char *hello = "hello";
    // socket对象
    // 网络连接在线程开启前

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        printf("create socket failed!\r\n");
        return;
    }
    // 创建一个socket进程

    memset(&servaddr, 0, sizeof(servaddr));
    // 初始化

    servaddr.sin_family = AF_INET;                // IPv4
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 接收任何IP
    servaddr.sin_port = htons(12345);             // 端口号

    // 监听本机12345端口，监听所有发送至此端口的UDP数据集合

    if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
    {
        printf("bind failed\r\n");
        return;
    }
    // UDP绑定

    printf("UDP server up and listening\n");
    // UPD绑定成功提示

    socklen_t addr_len;
    addr_len = sizeof(cliaddr);
    // 存储数据发送方的IP和端口等数据，方便回传

    if (getsockname(sockfd, (struct sockaddr *)&servaddr, &addr_len) < 0)
    {
        perror("getsockname failed");
        exit(EXIT_FAILURE);
    }
    // 临时对socket进行检测，防止在进入主要工作区前，socket出现错误

    char ip_str[INET_ADDRSTRLEN];
    inet_ntop(AF_INET, &servaddr.sin_addr, ip_str, sizeof(ip_str));
    printf("UDP server up and listening on IP: %s, Port: %d\n", ip_str, ntohs(servaddr.sin_port));
    // 监听数据，并打印数据发送方的IP和端口，与发送方发送的UDP数据集

    printf("Waiting for messages...\n");
    // 提示

    // 进入主要工作区
    while (1)
    {

        memset_s(buffer, sizeof(buffer), 0, sizeof(buffer));
        // 接收到的数据的初始化

        memset(&cliaddr, 0, sizeof(cliaddr));
        // 发送方地址存储结构的初始化

        socklen_t addrlen = sizeof(cliaddr);
        // 长度计算

        len = recvfrom(sockfd, buffer, 512, 0, (struct sockaddr *)&cliaddr, &addrlen);
        // 接收数据
        // recvfrom()函数各个参数的详细解释：

        // sockfd：
        // 类型：int
        // 描述：这是套接字文件描述符，它是通过socket()函数创建套接字时返回的值。

        // buf：
        // 类型：void *
        // 描述：这是一个指向缓冲区的指针，用于存储接收到的数据。
        // recvfrom()函数将把接收到的数据存储在这个缓冲区中。

        // len：
        // 类型：size_t
        // 描述：这是缓冲区的长度，即buf指向的内存区域可以存储的最大字节数。
        // 这个值应该足够大以存放预期接收的数据。

        // flags：
        // 类型：int
        // 描述：这是一个选项标志，通常设置为0。也可以设置特定的标志来修改recvfrom()的行为。
        // 例如MSG_DONTWAIT使recvfrom()变为非阻塞操作。

        // src_addr：
        // 类型：struct sockaddr *
        // 描述：这是一个指向sockaddr结构体的指针，用于存储发送方的地址信息。
        // 当recvfrom()成功返回后，这个结构体将被填充发送方的地址信息。如果不需要这个信息，可以传递NULL。

        // addrlen：
        // 类型：socklen_t *
        // 描述：这是一个指向socklen_t类型的指针，用于存储src_addr结构体的长度。
        // 在调用recvfrom()之前，这个值应该被初始化为src_addr结构体的大小。
        // 调用成功后，recvfrom()会更新这个值为实际填充到src_addr结构体的大小。

        if (len < 0)
        {
            perror("recvfrom failed");
            continue;
        }
        // 如果出现错误，跳过此次接收

        printf("Received message: %s\n", buffer);
        // 输出接收的消息

        char ip_str[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &cliaddr.sin_addr, ip_str, sizeof(ip_str));
        printf("Received message from %s:%d\n", ip_str, ntohs(cliaddr.sin_port));
        // 输出接收的消息

        command_lis(buffer);
        // 触发监听函数

        if (strcmp(buffer, COMMAND_SEND) == 0)
        {
            mqtt_send_task_intime(); // 如果深度监听到指令COMMAND_SEND，立即更新数据到MQTT服务器
        }
        sleep(1);
    }

    // 关闭这个 socket
    closesocket(socket_fd);
}

void read_task(void)
{
    while (1)
    {
        // AHT20服务
        static char line[32] = {0};

        // 初始化AHT20传感器
        while (IOT_SUCCESS != AHT20_Calibrate())
        {
            printf("AHT20 sensor init failed!\r\n");
            usleep(MS_PER_S);
        }

        // 获取温湿度传感器设备的数据
        retval = AHT20_StartMeasure();
        if (retval != IOT_SUCCESS)
        {
            printf("trigger measure failed!\r\n");
        }

        // 保存温度和湿度
        retval = AHT20_GetMeasureResult(&sensorData.tem, &sensorData.hum);
        if (retval != IOT_SUCCESS)
        {
            printf("get humidity data failed!\r\n");
        }

        unsigned short data = 0;

        // 初始化可燃气体传感器
        ret = hi_adc_read(5, &sensorData.ap, HI_ADC_EQU_MODEL_4, HI_ADC_CUR_BAIS_DEFAULT, 0);
        ret = hi_adc_read(0, &sensorData.ur, HI_ADC_EQU_MODEL_4, HI_ADC_CUR_BAIS_DEFAULT, 0);
        ret = hi_adc_read(2, &sensorData.gas, HI_ADC_EQU_MODEL_4, HI_ADC_CUR_BAIS_DEFAULT, 0);

        // gas 1.94
        // ap  28.9
        // ur  1.75
        // 报警阈值

        if ((sensorData.gas * 1e43 > 2.2) || (sensorData.ap * 1e43 < 24.8) || (sensorData.ur * 1e43 > 2.1))
        {
            IoTGpioSetOutputVal(SIG_TASK_GPIO, GPIO_LOW);
            sensorData.sig = 0;
        }

        sleep(1);
    }
}

// MQTT消息发布线程
void mqtt_send_task(void)
{
    while (1)
    {
        // MQTT连接
        //  组Topic
        memset_s(publish_topic, MQTT_DATA_MAX, 0, MQTT_DATA_MAX);
        if (sprintf_s(publish_topic, MQTT_DATA_MAX, MQTT_TOPIC_PUB_PROPERTIES, DEVICE_ID) > 0)
        {
            // 组JSON数据
            Packaged_json_data();
            // 发布消息
            MQTTClient_pub(publish_topic, mqtt_data, strlen((char *)mqtt_data));
        }
        osDelay(1000); // 延迟10秒
    }
}

// MQTT数据传输校验，保证数据传输的稳定，完整
int get_jsonData_value(const cJSON *const object, uint8_t *value)
{
    cJSON *json_value = NULL;
    int ret = -1;
    json_value = cJSON_GetObjectItem(object, "value");
    // 接收回传参数

    if (json_value)
    {
        if (!strcmp(json_value->valuestring, "ON")) // RollBack机制，若校验不成功，回滚到上一状态
        {
            *value = 1;
            json_value = NULL;
            ret = 0; // 0为成功
        }
        else if (!strcmp(json_value->valuestring, "OFF")) // RollBack机制，若校验不成功，回滚到上一状态
        {
            *value = 0;
            json_value = NULL;
            ret = 0;
        }
    }
    json_value = NULL;
    return ret; // -1为失败
}

// 解析JSON数据
int Parsing_json_data(const char *payload)
{
    cJSON *root = NULL, *command_name = NULL, *paras = NULL, *value = NULL;
    cJSON *red = NULL, *green = NULL, *blue = NULL;
    int ret_code = 1;
    // 工作指针初始化

    root = cJSON_Parse((const char *)payload);
    // JSON数据解析

    if (root)
    {
        // 解析JSON数据
        command_name = cJSON_GetObjectItem(root, "command_name");
        paras = cJSON_GetObjectItem(root, "paras");

        // 判断目前的JSON数据是否正常
        if (command_name)
        {
            if (!strcmp(command_name->valuestring, "led"))
            {
                ret_code = get_jsonData_value(paras, &sensorData.led);
            }
            else if (!strcmp(command_name->valuestring, "sig"))
            {
                ret_code = get_jsonData_value(paras, &sensorData.sig);
            }
        }
    }
    cJSON_Delete(root);
    root = command_name = paras = value = red = green = blue = NULL;
    // 工作指针结束

    // 对接收的指令进行判断，并进行相应的响应
    (sensorData.led == 1) ? IoTGpioSetOutputVal(LED_TASK_GPIO, GPIO_HIGH) : IoTGpioSetOutputVal(LED_TASK_GPIO, GPIO_LOW);
    (sensorData.sig == 1) ? IoTGpioSetOutputVal(SIG_TASK_GPIO, GPIO_LOW) : IoTGpioSetOutputVal(SIG_TASK_GPIO, GPIO_HIGH);
    // 配置高低电平

    // 更新MQTT数据
    mqtt_send_task_intime();
    return ret_code;
}

// 向云端发送返回值
// 以供华为iotda校验数据发送是否成功
void send_cloud_request_code(const char *request_id, int ret_code, int request_len)
{
    char *request_topic = (char *)malloc(strlen(MALLOC_MQTT_TOPIC_PUB_COMMANDS_REQ) +
                                         strlen(DEVICE_ID) + request_len + 1);

    // 内存校验与内存分配
    if (request_topic != NULL)
    {
        memset_s(request_topic,
                 strlen(DEVICE_ID) + strlen(MALLOC_MQTT_TOPIC_PUB_COMMANDS_REQ) + request_len + 1,
                 0,
                 strlen(DEVICE_ID) + strlen(MALLOC_MQTT_TOPIC_PUB_COMMANDS_REQ) + request_len + 1);
        if (sprintf_s(request_topic,
                      strlen(DEVICE_ID) + strlen(MALLOC_MQTT_TOPIC_PUB_COMMANDS_REQ) + request_len + 1,
                      MQTT_TOPIC_PUB_COMMANDS_REQ, DEVICE_ID, request_id) > 0)
        {
            if (ret_code == 0) // 判断回传的code是否为0或1，表示失败和成功，后触发带有ROLLBACK的函数
            {
                MQTTClient_pub(request_topic, "{\"result_code\":0}", strlen("{\"result_code\":0}"));
            }
            else if (ret_code == 1)
            {
                MQTTClient_pub(request_topic, "{\"result_code\":1}", strlen("{\"result_code\":1}"));
            }
        }
        free(request_topic);
        request_topic = NULL;
    }
}

// MQTT接收数据的回调函数
int8_t mqttClient_sub_callback(unsigned char *topic, unsigned char *payload)
{
    if ((topic == NULL) || (payload == NULL))
    {
        return -1;
    }
    else
    {
        printf("topic: %s\r\n", topic);
        printf("payload: %s\r\n", payload);

        // 提取出topic中的request_id
        char request_id[50] = {0};
        int ret_code = 1; // 1为失败
        if (0 == strcpy_s(request_id, sizeof(request_id),
                          topic + strlen(DEVICE_ID) + strlen("$oc/devices//sys/commands/request_id=")))
        {
            printf("request_id: %s\r\n", request_id);
            // 解析JSON数据
            ret_code = Parsing_json_data(payload);
            send_cloud_request_code(request_id, ret_code, sizeof(request_id));
        }
    }
    return 0;
}

// MQTT  接收消息任务
void mqtt_recv_task(void)
{
    while (1)
    {
        MQTTClient_sub();
        sleep(MQTT_RECV_TASK_TIME);
    }
}

static void network_wifi_mqtt_example(void)
{
    // 外设的初始化
    // Init初始化
    // GpioSetDir设置GPIO的输出模式
    IoTGpioInit(LED_TASK_GPIO);
    IoTGpioSetDir(LED_TASK_GPIO, IOT_GPIO_DIR_OUT);

    IoTGpioInit(SIG_TASK_GPIO);
    IoTGpioSetDir(SIG_TASK_GPIO, IOT_GPIO_DIR_OUT);
    // 设置GPIO0和GPIO2的状态为输出
    // 对应数字电压

    IoTGpioInit(GAS_SENSOR_CHAN_NAME);
    IoTGpioSetDir(GAS_SENSOR_CHAN_NAME, IOT_GPIO_DIR_IN);
    // 设置GPIO5状态为输入
    // 将模拟电压转化为数字值

    IoTGpioInit(11);
    IoTGpioSetDir(11, IOT_GPIO_DIR_IN);
    IoTGpioInit(12);
    IoTGpioSetDir(12, IOT_GPIO_DIR_IN);
    IoTGpioInit(5);
    IoTGpioSetDir(5, IOT_GPIO_DIR_IN);

    // 设置初始电平，LED,FAN,SIG均为关闭状态
    // 因默认LED为高电平触发，FAN和SIG为低电平触发，故LED设置初始值为LOW，FAN和SIG初始值为HIGH
    IoTGpioSetOutputVal(LED_TASK_GPIO, GPIO_LOW);
    IoTGpioSetOutputVal(SIG_TASK_GPIO, GPIO_HIGH);

    // 初始化和设置I2C总线，将GPIO13设置为SDA总线，GPIO14设置为SCL总线
    IoTGpioInit(IOT_GPIO_IDX_13);
    hi_io_set_func(IOT_GPIO_IDX_13, HI_IO_FUNC_GPIO_13_I2C0_SDA);
    IoTGpioInit(IOT_GPIO_IDX_14);
    hi_io_set_func(IOT_GPIO_IDX_14, HI_IO_FUNC_GPIO_14_I2C0_SCL);
    // 总线的复用

    p_MQTTClient_sub_callback = &mqttClient_sub_callback;
    // 回滚机制

    // 连接WiFi
    if (WiFi_connectHotspots(WIFI_NAME, WIFI_PASSWORD) != WIFI_SUCCESS)
    {
        printf("[error] connectWiFiHotspots\r\n");
    }
    sleep(TASK_INIT_TIME);

    // 连接MQTT服务器
    if (MQTTClient_connectServer(SERVER_IP_ADDR, SERVER_IP_PORT) != WIFI_SUCCESS)
    {
        printf("[error] mqttClient_connectServer\r\n");
    }
    sleep(TASK_INIT_TIME);

    // 初始化MQTT客户端
    if (MQTTClient_init(MQTT_CLIENT_ID, MQTT_USER_NAME, MQTT_PASS_WORD) != WIFI_SUCCESS)
    {
        printf("[error] mqttClient_init\r\n");
    }
    sleep(TASK_INIT_TIME);

    // 订阅主题
    if (MQTTClient_subscribe(MQTT_TOPIC_SUB_COMMANDS) != WIFI_SUCCESS)
    {
        printf("[error] mqttClient_subscribe\r\n");
    }
    sleep(TASK_INIT_TIME);

    //  创建线程，创建第一个线程，配置头指针
    osThreadAttr_t options;
    options.name = "mqtt_send_task";
    options.attr_bits = 0;
    options.cb_mem = NULL;
    options.cb_size = 0;
    options.stack_mem = NULL;
    options.stack_size = TASK_STACK_SIZE;
    options.priority = osPriorityNormal;

    mqtt_send_task_id = osThreadNew((osThreadFunc_t)mqtt_send_task, NULL, &options);
    if (mqtt_send_task_id != NULL)
    {
        printf("ID = %d, Create mqtt_send_task_id is OK!\r\n", mqtt_send_task_id);
    }

    // 创建MQTT的接收任务的线程
    options.name = "mqtt_recv_task";
    options.stack_size = TASK_STACK_SIZE;
    mqtt_recv_task_id = osThreadNew((osThreadFunc_t)mqtt_recv_task, NULL, &options);
    if (mqtt_recv_task_id != NULL)
    {
        printf("ID = %d, Create mqtt_recv_task_id is OK!\r\n", mqtt_recv_task_id);
    }

    // 创建UDP服务的接收和处理线程
    options.name = "thread_1";
    options.stack_size = TASK_STACK_SIZE;
    udp_id = osThreadNew((osThreadFunc_t)udp_task_rev, NULL, &options);
    if (udp_id != NULL)
    {
        printf("ID = %d, Create Task1_ID is OK!\r\n", udp_id);
    }

    options.name = "read_task";
    options.stack_size = TASK_STACK_SIZE;
    read_task_id = osThreadNew((osThreadFunc_t)read_task, NULL, &options);
    if (udp_id != NULL)
    {
        printf("ID = %d, Create read_task is OK!\r\n", read_task_id);
    }
}
SYS_RUN(network_wifi_mqtt_example);
